#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#include "wx/log.h"
#endif

#include "wx/colordlg.h"
#include "wx/numdlg.h"
#include "wx/artprov.h"
#include "wx/image.h"
#include "wx/imaglist.h"
#include "wx/math.h"
#include "wx/renderer.h"

#include "oxDefs.h"
#include "Tree.h"

#if USE_GENERIC_TREECTRL
IMPLEMENT_DYNAMIC_CLASS(oxTreeCtrl, wxGenericTreeCtrl)
#else
IMPLEMENT_DYNAMIC_CLASS(oxTreeCtrl, wxTreeCtrl)
#endif


#if USE_GENERIC_TREECTRL
	BEGIN_EVENT_TABLE(oxTreeCtrl, wxGenericTreeCtrl)
#else
	BEGIN_EVENT_TABLE(oxTreeCtrl, wxTreeCtrl)
#endif
	EVT_TREE_BEGIN_DRAG(oxTree_Ctrl, oxTreeCtrl::OnBeginDrag)
	EVT_TREE_END_DRAG(oxTree_Ctrl, oxTreeCtrl::OnEndDrag)
	EVT_TREE_BEGIN_LABEL_EDIT(oxTree_Ctrl, oxTreeCtrl::OnBeginLabelEdit)
	EVT_TREE_END_LABEL_EDIT(oxTree_Ctrl, oxTreeCtrl::OnEndLabelEdit)
	EVT_TREE_DELETE_ITEM(oxTree_Ctrl, oxTreeCtrl::OnDeleteItem)


	EVT_TREE_SEL_CHANGED(oxTree_Ctrl, oxTreeCtrl::OnSelChanged)

	// so many different ways to handle right mouse button clicks...
	EVT_CONTEXT_MENU(oxTreeCtrl::OnContextMenu)
	// EVT_TREE_ITEM_MENU is the preferred event for creating context menus
	// on a tree control, because it includes the point of the click or item,
	// meaning that no additional placement calculations are required.
	EVT_TREE_ITEM_MENU(oxTree_Ctrl, oxTreeCtrl::OnItemMenu)
	EVT_TREE_ITEM_RIGHT_CLICK(oxTree_Ctrl, oxTreeCtrl::OnItemRClick)

	EVT_RIGHT_DOWN(oxTreeCtrl::OnRMouseDown)

END_EVENT_TABLE()


// 	
	
oxTreeCtrl::oxTreeCtrl(wxWindow *parent, const wxWindowID id,
	const wxPoint& pos, const wxSize& size,
	long style)
	: wxTreeCtrl(parent, id, pos, size, style)
{
}

int oxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
	const wxTreeItemId& item2)
{
	if ( m_reverseSort )
	{
		// just exchange 1st and 2nd items
		return wxTreeCtrl::OnCompareItems(item2, item1);
	}
	else
	{
		return wxTreeCtrl::OnCompareItems(item1, item2);
	}
}

void oxTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
	// need to explicitly allow drag
	m_draggedItem = event.GetItem();

	event.Allow();
}

void oxTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
	wxTreeItemId itemSrc = m_draggedItem,
		itemDst = event.GetItem();
	m_draggedItem = (wxTreeItemId)0l;

	// where to copy the item?
	if ( itemDst.IsOk() && !ItemHasChildren(itemDst) )
	{
		// copy to the parent then
		itemDst = GetItemParent(itemDst);
	}

	if ( !itemDst.IsOk() )
	{
		wxLogMessage(wxT("OnEndDrag: can't drop here."));

		return;
	}

	wxString text = GetItemText(itemSrc);
	wxLogMessage(wxT("OnEndDrag: '%s' copied to '%s'."),
		text.c_str(), GetItemText(itemDst).c_str());

	// just do append here - we could also insert it just before/after the item
	// on which it was dropped, but this requires slightly more work... we also
	// completely ignore the client data and icon of the old item but could
	// copy them as well.
	//
	// Finally, we only copy one item here but we might copy the entire tree if
	// we were dragging a folder.
	//int image = wxGetApp().ShowImages() ? TreeCtrlIcon_File : -1;
	wxTreeItemId id = AppendItem(itemDst, text/*, image*/);

// 	if ( wxGetApp().ShowStates() )
// 		SetItemState(id, GetItemState(itemSrc));
}

void oxTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
{
	wxLogMessage(wxT("OnBeginLabelEdit"));

	// for testing, prevent this item's label editing
	wxTreeItemId itemId = event.GetItem();
	
}

void oxTreeCtrl::OnEndLabelEdit(wxTreeEvent& event)
{
	wxLogMessage(wxT("OnEndLabelEdit"));

	// don't allow anything except letters in the labels
	if ( !event.GetLabel().IsWord() )
	{
		wxMessageBox(wxT("The new label should be a single word."));

		event.Veto();
	}
}

void oxTreeCtrl::OnDeleteItem(wxTreeEvent& event)
{
	event.Skip();
}

void oxTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	event.Skip();
}

void oxTreeCtrl::OnSelChanging(wxTreeEvent& event)
{
	event.Skip();
}

void oxTreeCtrl::OnRMouseDown(wxMouseEvent& event)
{
	wxLogMessage(wxT("Right mouse button down"));
	event.Skip();
}

void oxTreeCtrl::OnItemMenu(wxTreeEvent& event)
{
	wxTreeItemId itemId = event.GetItem();
	wxCHECK_RET( itemId.IsOk(), "should have a valid item" );

	oxTreeItemData *item = (oxTreeItemData *)GetItemData(itemId);
	wxPoint clientpt = event.GetPoint();
	wxPoint screenpt = ClientToScreen(clientpt);

	wxLogMessage(wxT("OnItemMenu for item \"%s\" at screen coords (%i, %i)"),
		item->GetDesc(), screenpt.x, screenpt.y);

	ShowMenu(itemId, clientpt);
	event.Skip();
}

void oxTreeCtrl::OnContextMenu(wxContextMenuEvent& event)
{
	wxPoint pt = event.GetPosition();

	wxLogMessage(wxT("OnContextMenu at screen coords (%i, %i)"), pt.x, pt.y);

	event.Skip();
}

void oxTreeCtrl::ShowMenu(wxTreeItemId id, const wxPoint& pt)
{
	wxString title;
	if ( id.IsOk() )
	{
		title << wxT("Menu for ") << GetItemText(id);
	}
	else
	{
		title = wxT("Menu for no particular item");
	}

#if wxUSE_MENUS
	wxMenu menu(title);
	menu.Append(oxTree_Rename, wxT("&Rename"));
	menu.AppendSeparator();
	menu.Append(oxTree_Duplicate, wxT("&Duplicate"));
	menu.Append(oxTree_Delete, wxT("&Delete"));

	PopupMenu(&menu, pt);
#endif // wxUSE_MENUS
}

void oxTreeCtrl::OnItemRClick(wxTreeEvent& event)
{
	wxTreeItemId itemId = event.GetItem();
	wxCHECK_RET( itemId.IsOk(), "should have a valid item" );

	oxTreeItemData *item = (oxTreeItemData *)GetItemData(itemId);

	wxLogMessage(wxT("Item \"%s\" right clicked"), item->GetDesc());

	event.Skip();
}

void LogKeyEvent(const wxChar *name, const wxKeyEvent& event)
{
	wxString key;
	long keycode = event.GetKeyCode();
	{
		switch ( keycode )
		{
		case WXK_BACK: key = wxT("BACK"); break;
		case WXK_TAB: key = wxT("TAB"); break;
		case WXK_RETURN: key = wxT("RETURN"); break;
		case WXK_ESCAPE: key = wxT("ESCAPE"); break;
		case WXK_SPACE: key = wxT("SPACE"); break;
		case WXK_DELETE: key = wxT("DELETE"); break;
		case WXK_START: key = wxT("START"); break;
		case WXK_LBUTTON: key = wxT("LBUTTON"); break;
		case WXK_RBUTTON: key = wxT("RBUTTON"); break;
		case WXK_CANCEL: key = wxT("CANCEL"); break;
		case WXK_MBUTTON: key = wxT("MBUTTON"); break;
		case WXK_CLEAR: key = wxT("CLEAR"); break;
		case WXK_SHIFT: key = wxT("SHIFT"); break;
		case WXK_ALT: key = wxT("ALT"); break;
		case WXK_CONTROL: key = wxT("CONTROL"); break;
		case WXK_MENU: key = wxT("MENU"); break;
		case WXK_PAUSE: key = wxT("PAUSE"); break;
		case WXK_CAPITAL: key = wxT("CAPITAL"); break;
		case WXK_END: key = wxT("END"); break;
		case WXK_HOME: key = wxT("HOME"); break;
		case WXK_LEFT: key = wxT("LEFT"); break;
		case WXK_UP: key = wxT("UP"); break;
		case WXK_RIGHT: key = wxT("RIGHT"); break;
		case WXK_DOWN: key = wxT("DOWN"); break;
		case WXK_SELECT: key = wxT("SELECT"); break;
		case WXK_PRINT: key = wxT("PRINT"); break;
		case WXK_EXECUTE: key = wxT("EXECUTE"); break;
		case WXK_SNAPSHOT: key = wxT("SNAPSHOT"); break;
		case WXK_INSERT: key = wxT("INSERT"); break;
		case WXK_HELP: key = wxT("HELP"); break;
		case WXK_NUMPAD0: key = wxT("NUMPAD0"); break;
		case WXK_NUMPAD1: key = wxT("NUMPAD1"); break;
		case WXK_NUMPAD2: key = wxT("NUMPAD2"); break;
		case WXK_NUMPAD3: key = wxT("NUMPAD3"); break;
		case WXK_NUMPAD4: key = wxT("NUMPAD4"); break;
		case WXK_NUMPAD5: key = wxT("NUMPAD5"); break;
		case WXK_NUMPAD6: key = wxT("NUMPAD6"); break;
		case WXK_NUMPAD7: key = wxT("NUMPAD7"); break;
		case WXK_NUMPAD8: key = wxT("NUMPAD8"); break;
		case WXK_NUMPAD9: key = wxT("NUMPAD9"); break;
		case WXK_MULTIPLY: key = wxT("MULTIPLY"); break;
		case WXK_ADD: key = wxT("ADD"); break;
		case WXK_SEPARATOR: key = wxT("SEPARATOR"); break;
		case WXK_SUBTRACT: key = wxT("SUBTRACT"); break;
		case WXK_DECIMAL: key = wxT("DECIMAL"); break;
		case WXK_DIVIDE: key = wxT("DIVIDE"); break;
		case WXK_F1: key = wxT("F1"); break;
		case WXK_F2: key = wxT("F2"); break;
		case WXK_F3: key = wxT("F3"); break;
		case WXK_F4: key = wxT("F4"); break;
		case WXK_F5: key = wxT("F5"); break;
		case WXK_F6: key = wxT("F6"); break;
		case WXK_F7: key = wxT("F7"); break;
		case WXK_F8: key = wxT("F8"); break;
		case WXK_F9: key = wxT("F9"); break;
		case WXK_F10: key = wxT("F10"); break;
		case WXK_F11: key = wxT("F11"); break;
		case WXK_F12: key = wxT("F12"); break;
		case WXK_F13: key = wxT("F13"); break;
		case WXK_F14: key = wxT("F14"); break;
		case WXK_F15: key = wxT("F15"); break;
		case WXK_F16: key = wxT("F16"); break;
		case WXK_F17: key = wxT("F17"); break;
		case WXK_F18: key = wxT("F18"); break;
		case WXK_F19: key = wxT("F19"); break;
		case WXK_F20: key = wxT("F20"); break;
		case WXK_F21: key = wxT("F21"); break;
		case WXK_F22: key = wxT("F22"); break;
		case WXK_F23: key = wxT("F23"); break;
		case WXK_F24: key = wxT("F24"); break;
		case WXK_NUMLOCK: key = wxT("NUMLOCK"); break;
		case WXK_SCROLL: key = wxT("SCROLL"); break;
		case WXK_PAGEUP: key = wxT("PAGEUP"); break;
		case WXK_PAGEDOWN: key = wxT("PAGEDOWN"); break;
		case WXK_NUMPAD_SPACE: key = wxT("NUMPAD_SPACE"); break;
		case WXK_NUMPAD_TAB: key = wxT("NUMPAD_TAB"); break;
		case WXK_NUMPAD_ENTER: key = wxT("NUMPAD_ENTER"); break;
		case WXK_NUMPAD_F1: key = wxT("NUMPAD_F1"); break;
		case WXK_NUMPAD_F2: key = wxT("NUMPAD_F2"); break;
		case WXK_NUMPAD_F3: key = wxT("NUMPAD_F3"); break;
		case WXK_NUMPAD_F4: key = wxT("NUMPAD_F4"); break;
		case WXK_NUMPAD_HOME: key = wxT("NUMPAD_HOME"); break;
		case WXK_NUMPAD_LEFT: key = wxT("NUMPAD_LEFT"); break;
		case WXK_NUMPAD_UP: key = wxT("NUMPAD_UP"); break;
		case WXK_NUMPAD_RIGHT: key = wxT("NUMPAD_RIGHT"); break;
		case WXK_NUMPAD_DOWN: key = wxT("NUMPAD_DOWN"); break;
		case WXK_NUMPAD_PAGEUP: key = wxT("NUMPAD_PAGEUP"); break;
		case WXK_NUMPAD_PAGEDOWN: key = wxT("NUMPAD_PAGEDOWN"); break;
		case WXK_NUMPAD_END: key = wxT("NUMPAD_END"); break;
		case WXK_NUMPAD_BEGIN: key = wxT("NUMPAD_BEGIN"); break;
		case WXK_NUMPAD_INSERT: key = wxT("NUMPAD_INSERT"); break;
		case WXK_NUMPAD_DELETE: key = wxT("NUMPAD_DELETE"); break;
		case WXK_NUMPAD_EQUAL: key = wxT("NUMPAD_EQUAL"); break;
		case WXK_NUMPAD_MULTIPLY: key = wxT("NUMPAD_MULTIPLY"); break;
		case WXK_NUMPAD_ADD: key = wxT("NUMPAD_ADD"); break;
		case WXK_NUMPAD_SEPARATOR: key = wxT("NUMPAD_SEPARATOR"); break;
		case WXK_NUMPAD_SUBTRACT: key = wxT("NUMPAD_SUBTRACT"); break;
		case WXK_NUMPAD_DECIMAL: key = wxT("NUMPAD_DECIMAL"); break;

		default:
			{
				if ( keycode < 128 && wxIsprint((int)keycode) )
					key.Printf(wxT("'%c'"), (char)keycode);
				else if ( keycode > 0 && keycode < 27 )
					key.Printf(_("Ctrl-%c"), wxT('A') + keycode - 1);
				else
					key.Printf(wxT("unknown (%ld)"), keycode);
			}
		}
	}

	wxLogMessage( wxT("%s event: %s (flags = %c%c%c%c)"),
		name,
		key.c_str(),
		event.ControlDown() ? wxT('C') : wxT('-'),
		event.AltDown() ? wxT('A') : wxT('-'),
		event.ShiftDown() ? wxT('S') : wxT('-'),
		event.MetaDown() ? wxT('M') : wxT('-'));
}

void oxTreeCtrl::OnTreeKeyDown(wxTreeEvent& event)
{
	LogKeyEvent(wxT("Tree key down "), event.GetKeyEvent());

	event.Skip();
}